/**
 * Created by ${PRODUCT_NAME}.
 * User: skylerparr
 * Date: 2/2/11
 * Time: 9:09 AM
 * To change this template use File | Settings | File Templates.
 */
package com.thoughtorigin.display.containers {
import flash.display.DisplayObject;

import flash.display.Shape;

import mx.containers.utilityClasses.Layout;

import org.flexunit.asserts.assertEquals;
import org.flexunit.asserts.assertTrue;
import org.flexunit.async.Async;

public class DefaultLayoutContainerTest {

    private var _layoutContainer: DefaultLayoutContainer;
    private var _container: Container;

    [Before]
    public function setUp(): void {
        _container = new Container();
        _layoutContainer = new DefaultLayoutContainer(_container);
    }

    [After]
    public function tearDown(): void {
        _container = null;
        _layoutContainer = null;
    }

    [Test]
    public function shouldSetHaveDefaultLayoutPolicyToHorizontalAndCanBeSet(): void {
        assertEquals(LayoutPolicy.HORIZONTAL_LAYOUT, _layoutContainer.layoutPolicy);
        _layoutContainer.layoutPolicy = LayoutPolicy.VERTICAL_LAYOUT;
        assertEquals(LayoutPolicy.VERTICAL_LAYOUT, _layoutContainer.layoutPolicy);
    }

    [Test]
    public function shouldOnlyChangeIfSetToValidValue(): void {
        assertEquals(LayoutPolicy.HORIZONTAL_LAYOUT, _layoutContainer.layoutPolicy);
        _layoutContainer.layoutPolicy = "wrong";
        assertEquals(LayoutPolicy.HORIZONTAL_LAYOUT, _layoutContainer.layoutPolicy);
        _layoutContainer.layoutPolicy = LayoutPolicy.VERTICAL_LAYOUT;
        assertEquals(LayoutPolicy.VERTICAL_LAYOUT, _layoutContainer.layoutPolicy);
        _layoutContainer.layoutPolicy = "wrong again";
        assertEquals(LayoutPolicy.VERTICAL_LAYOUT, _layoutContainer.layoutPolicy);
    }

    [Test(async)]
    public function shouldDispatchLayoutRefreshEventWhenChangingLayoutPolicy(): void {
        _layoutContainer.addEventListener(LayoutEvent.LAYOUT_REFRESH, Async.asyncHandler(this, function(le: LayoutEvent, obj: Object): void {
            _layoutContainer.removeEventListener(LayoutEvent.LAYOUT_REFRESH, arguments.callee);
            assertTrue(true);
        }, 200));

        _layoutContainer.layoutPolicy = LayoutPolicy.VERTICAL_LAYOUT;
    }

    [Test(async)]
    public function byDefaultTheItemsShouldLayoutHorizontallyByChildWidth(): void {
        _layoutContainer.addEventListener(LayoutEvent.LAYOUT_REFRESH, Async.asyncHandler(this, function(le: LayoutEvent, obj: Object): void {
            _layoutContainer.removeEventListener(LayoutEvent.LAYOUT_REFRESH, arguments.callee);

            assertEquals(0, _container.getChildAt(0).x);
            assertEquals(100, _container.getChildAt(1).x);
            assertEquals(110, _container.getChildAt(2).x);

            assertEquals(0, _container.getChildAt(0).y);
            assertEquals(0, _container.getChildAt(1).y);
            assertEquals(0, _container.getChildAt(2).y);
        }, 200));

        _container.rawChildContainer.addChild(getDisplayObject(100, 100));
        _container.rawChildContainer.addChild(getDisplayObject(10, 10));
        _container.rawChildContainer.addChild(getDisplayObject(50, 50));

        _layoutContainer.refresh();
    }

    [Test(async)]
    public function shouldRefreshHorizontalLayoutWhenContainerChanges(): void {
        _layoutContainer.addEventListener(LayoutEvent.LAYOUT_REFRESH, Async.asyncHandler(this, function(le: LayoutEvent, obj: Object): void {
            _layoutContainer.removeEventListener(LayoutEvent.LAYOUT_REFRESH, arguments.callee);

            assertEquals(0, _container.getChildAt(0).x);
            assertEquals(100, _container.getChildAt(1).x);
            assertEquals(110, _container.getChildAt(2).x);
            assertEquals(160, _container.getChildAt(3).x);

            assertEquals(0, _container.getChildAt(0).y);
            assertEquals(0, _container.getChildAt(1).y);
            assertEquals(0, _container.getChildAt(2).y);
            assertEquals(0, _container.getChildAt(3).y);
        }, 200));

        _container.rawChildContainer.addChild(getDisplayObject(100, 100));
        _container.rawChildContainer.addChild(getDisplayObject(10, 10));
        _container.rawChildContainer.addChild(getDisplayObject(50, 50));

        _container.addChild(getDisplayObject(50, 50));
    }

    [Test(async)]
    public function byDefaultTheItemsShouldLayoutHorizontallyByChildWidthAndIgnoreTheXButKeepTheY(): void {
        _layoutContainer.addEventListener(LayoutEvent.LAYOUT_REFRESH, Async.asyncHandler(this, function(le: LayoutEvent, obj: Object): void {
            _layoutContainer.removeEventListener(LayoutEvent.LAYOUT_REFRESH, arguments.callee);

            assertEquals(0, _container.getChildAt(0).x);
            assertEquals(100, _container.getChildAt(1).x);
            assertEquals(110, _container.getChildAt(2).x);

            assertEquals(343, _container.getChildAt(0).y);
            assertEquals(325, _container.getChildAt(1).y);
            assertEquals(34, _container.getChildAt(2).y);
        }, 200));

        _container.rawChildContainer.addChild(getDisplayObject(100, 100, 134, 343));
        _container.rawChildContainer.addChild(getDisplayObject(10, 10,432, 325));
        _container.rawChildContainer.addChild(getDisplayObject(50, 50, 3432, 34));

        _layoutContainer.refresh();
    }

    [Test(async)]
    public function itemsShouldLayoutVerticallyIfSetToVerticalLayout(): void {
        _layoutContainer.layoutPolicy = LayoutPolicy.VERTICAL_LAYOUT;

        _layoutContainer.addEventListener(LayoutEvent.LAYOUT_REFRESH, Async.asyncHandler(this, function(le: LayoutEvent, obj: Object): void {
            _layoutContainer.removeEventListener(LayoutEvent.LAYOUT_REFRESH, arguments.callee);

            assertEquals(0, _container.getChildAt(0).x);
            assertEquals(0, _container.getChildAt(1).x);
            assertEquals(0, _container.getChildAt(2).x);

            assertEquals(0, _container.getChildAt(0).y);
            assertEquals(100, _container.getChildAt(1).y);
            assertEquals(110, _container.getChildAt(2).y);
        }, 200));

        _container.rawChildContainer.addChild(getDisplayObject(100, 100));
        _container.rawChildContainer.addChild(getDisplayObject(10, 10));
        _container.rawChildContainer.addChild(getDisplayObject(50, 50));

        _layoutContainer.refresh();
    }

    [Test(async)]
    public function shouldRefreshVerticalLayoutWhenContainerChanges(): void {
        _layoutContainer.layoutPolicy = LayoutPolicy.VERTICAL_LAYOUT;
        _layoutContainer.addEventListener(LayoutEvent.LAYOUT_REFRESH, Async.asyncHandler(this, function(le: LayoutEvent, obj: Object): void {
            _layoutContainer.removeEventListener(LayoutEvent.LAYOUT_REFRESH, arguments.callee);

            assertEquals(0, _container.getChildAt(0).x);
            assertEquals(0, _container.getChildAt(1).x);
            assertEquals(0, _container.getChildAt(2).x);
            assertEquals(0, _container.getChildAt(3).x);

            assertEquals(0, _container.getChildAt(0).y);
            assertEquals(100, _container.getChildAt(1).y);
            assertEquals(110, _container.getChildAt(2).y);
            assertEquals(160, _container.getChildAt(3).y);
        }, 200));

        _container.rawChildContainer.addChild(getDisplayObject(100, 100));
        _container.rawChildContainer.addChild(getDisplayObject(10, 10));
        _container.rawChildContainer.addChild(getDisplayObject(50, 50));

        _container.addChild(getDisplayObject(50, 50));
    }

    [Test(async)]
    public function theItemsShouldLayoutVerticallyByChildHeightAndIgnoreTheYButKeepTheX(): void {
        _layoutContainer.layoutPolicy = LayoutPolicy.VERTICAL_LAYOUT;
        _layoutContainer.addEventListener(LayoutEvent.LAYOUT_REFRESH, Async.asyncHandler(this, function(le: LayoutEvent, obj: Object): void {
            _layoutContainer.removeEventListener(LayoutEvent.LAYOUT_REFRESH, arguments.callee);

            assertEquals(134, _container.getChildAt(0).x);
            assertEquals(432, _container.getChildAt(1).x);
            assertEquals(3432, _container.getChildAt(2).x);

            assertEquals(0, _container.getChildAt(0).y);
            assertEquals(100, _container.getChildAt(1).y);
            assertEquals(110, _container.getChildAt(2).y);
        }, 200));

        _container.rawChildContainer.addChild(getDisplayObject(100, 100, 134, 343));
        _container.rawChildContainer.addChild(getDisplayObject(10, 10,432, 325));
        _container.rawChildContainer.addChild(getDisplayObject(50, 50, 3432, 34));

        _layoutContainer.refresh();
    }

    [Test(async)]
    public function shouldLayoutItemsHorizontallyAndAddAGapBetweenItems(): void {
        _layoutContainer.addEventListener(LayoutEvent.LAYOUT_REFRESH, Async.asyncHandler(this, function(le: LayoutEvent, obj: Object): void {
            _layoutContainer.removeEventListener(LayoutEvent.LAYOUT_REFRESH, arguments.callee);

            assertEquals(0, _container.getChildAt(0).x);
            assertEquals(110, _container.getChildAt(1).x);
            assertEquals(130, _container.getChildAt(2).x);

            assertEquals(0, _container.getChildAt(0).y);
            assertEquals(0, _container.getChildAt(1).y);
            assertEquals(0, _container.getChildAt(2).y);
        }, 200));

        _container.rawChildContainer.addChild(getDisplayObject(100, 100));
        _container.rawChildContainer.addChild(getDisplayObject(10, 10));
        _container.rawChildContainer.addChild(getDisplayObject(50, 50));

        _layoutContainer.gap = 10;
        _layoutContainer.refresh();
    }

    [Test(async)]
    public function shouldLayoutItemsVerticallyAndAddAGapBetweenItems(): void {
        _layoutContainer.layoutPolicy = LayoutPolicy.VERTICAL_LAYOUT;
        _layoutContainer.addEventListener(LayoutEvent.LAYOUT_REFRESH, Async.asyncHandler(this, function(le: LayoutEvent, obj: Object): void {
            _layoutContainer.removeEventListener(LayoutEvent.LAYOUT_REFRESH, arguments.callee);

            assertEquals(0, _container.getChildAt(0).x);
            assertEquals(0, _container.getChildAt(1).x);
            assertEquals(0, _container.getChildAt(2).x);

            assertEquals(0, _container.getChildAt(0).y);
            assertEquals(110, _container.getChildAt(1).y);
            assertEquals(130, _container.getChildAt(2).y);
        }, 200));

        _container.rawChildContainer.addChild(getDisplayObject(100, 100));
        _container.rawChildContainer.addChild(getDisplayObject(10, 10));
        _container.rawChildContainer.addChild(getDisplayObject(50, 50));

        _layoutContainer.gap = 10;
        _layoutContainer.refresh();
    }

    [Test(async)]
    public function shouldRefreshLayoutWhenChangingTheGap(): void {
        _layoutContainer.addEventListener(LayoutEvent.LAYOUT_REFRESH, Async.asyncHandler(this, function(le: LayoutEvent, obj: Object): void {
            _layoutContainer.removeEventListener(LayoutEvent.LAYOUT_REFRESH, arguments.callee);

            assertEquals(0, _container.getChildAt(0).x);
            assertEquals(110, _container.getChildAt(1).x);
            assertEquals(130, _container.getChildAt(2).x);

            assertEquals(0, _container.getChildAt(0).y);
            assertEquals(0, _container.getChildAt(1).y);
            assertEquals(0, _container.getChildAt(2).y);
        }, 200));

        _container.rawChildContainer.addChild(getDisplayObject(100, 100));
        _container.rawChildContainer.addChild(getDisplayObject(10, 10));
        _container.rawChildContainer.addChild(getDisplayObject(50, 50));

        _layoutContainer.gap = 10;
    }

    [Test(async)]
    public function shouldEnforceCellWidthWhenLayingOutHorizontally(): void {
        _layoutContainer.addEventListener(LayoutEvent.LAYOUT_REFRESH, Async.asyncHandler(this, function(le: LayoutEvent, obj: Object): void {
            _layoutContainer.removeEventListener(LayoutEvent.LAYOUT_REFRESH, arguments.callee);

            assertEquals(0, _container.getChildAt(0).x);
            assertEquals(40, _container.getChildAt(1).x);
            assertEquals(80, _container.getChildAt(2).x);

            assertEquals(0, _container.getChildAt(0).y);
            assertEquals(0, _container.getChildAt(1).y);
            assertEquals(0, _container.getChildAt(2).y);
        }, 200));

        _container.rawChildContainer.addChild(getDisplayObject(100, 100));
        _container.rawChildContainer.addChild(getDisplayObject(10, 10));
        _container.rawChildContainer.addChild(getDisplayObject(50, 50));

        _layoutContainer.cellWidth = 40;
        _layoutContainer.refresh();
    }

    [Test(async)]
    public function shouldEnforceCellHeightWhenLayingOutVertically(): void {
        _layoutContainer.layoutPolicy = LayoutPolicy.VERTICAL_LAYOUT;
        _layoutContainer.addEventListener(LayoutEvent.LAYOUT_REFRESH, Async.asyncHandler(this, function(le: LayoutEvent, obj: Object): void {
            _layoutContainer.removeEventListener(LayoutEvent.LAYOUT_REFRESH, arguments.callee);

            assertEquals(0, _container.getChildAt(0).x);
            assertEquals(0, _container.getChildAt(1).x);
            assertEquals(0, _container.getChildAt(2).x);

            assertEquals(0, _container.getChildAt(0).y);
            assertEquals(40, _container.getChildAt(1).y);
            assertEquals(80, _container.getChildAt(2).y);
        }, 200));

        _container.rawChildContainer.addChild(getDisplayObject(100, 100));
        _container.rawChildContainer.addChild(getDisplayObject(10, 10));
        _container.rawChildContainer.addChild(getDisplayObject(50, 50));

        _layoutContainer.cellHeight = 40;
        _layoutContainer.refresh();
    }

    [Test(async)]
    public function shouldEnforceCellWidthWhenLayingOutHorizontallyAndAddGap(): void {
        _layoutContainer.gap = 10;
        _layoutContainer.addEventListener(LayoutEvent.LAYOUT_REFRESH, Async.asyncHandler(this, function(le: LayoutEvent, obj: Object): void {
            _layoutContainer.removeEventListener(LayoutEvent.LAYOUT_REFRESH, arguments.callee);

            assertEquals(0, _container.getChildAt(0).x);
            assertEquals(50, _container.getChildAt(1).x);
            assertEquals(100, _container.getChildAt(2).x);

            assertEquals(0, _container.getChildAt(0).y);
            assertEquals(0, _container.getChildAt(1).y);
            assertEquals(0, _container.getChildAt(2).y);
        }, 200));

        _container.rawChildContainer.addChild(getDisplayObject(100, 100));
        _container.rawChildContainer.addChild(getDisplayObject(10, 10));
        _container.rawChildContainer.addChild(getDisplayObject(50, 50));

        _layoutContainer.cellWidth = 40;
        _layoutContainer.refresh();
    }

    [Test(async)]
    public function shouldEnforceCellHeightWhenLayingOutVerticallyAndAddGap(): void {
        _layoutContainer.layoutPolicy = LayoutPolicy.VERTICAL_LAYOUT;
        _layoutContainer.gap = 10;
        _layoutContainer.addEventListener(LayoutEvent.LAYOUT_REFRESH, Async.asyncHandler(this, function(le: LayoutEvent, obj: Object): void {
            _layoutContainer.removeEventListener(LayoutEvent.LAYOUT_REFRESH, arguments.callee);

            assertEquals(0, _container.getChildAt(0).x);
            assertEquals(0, _container.getChildAt(1).x);
            assertEquals(0, _container.getChildAt(2).x);

            assertEquals(0, _container.getChildAt(0).y);
            assertEquals(50, _container.getChildAt(1).y);
            assertEquals(100, _container.getChildAt(2).y);
        }, 200));

        _container.rawChildContainer.addChild(getDisplayObject(100, 100));
        _container.rawChildContainer.addChild(getDisplayObject(10, 10));
        _container.rawChildContainer.addChild(getDisplayObject(50, 50));

        _layoutContainer.cellHeight = 40;
        _layoutContainer.refresh();
    }

    [Test(async)]
    public function shouldDispatchLayoutRefreshWhenCellWidthChanges(): void {
        _layoutContainer.gap = 10;
        _layoutContainer.addEventListener(LayoutEvent.LAYOUT_REFRESH, Async.asyncHandler(this, function(le: LayoutEvent, obj: Object): void {
            _layoutContainer.removeEventListener(LayoutEvent.LAYOUT_REFRESH, arguments.callee);

            assertEquals(0, _container.getChildAt(0).x);
            assertEquals(50, _container.getChildAt(1).x);
            assertEquals(100, _container.getChildAt(2).x);

            assertEquals(0, _container.getChildAt(0).y);
            assertEquals(0, _container.getChildAt(1).y);
            assertEquals(0, _container.getChildAt(2).y);
        }, 200));

        _container.rawChildContainer.addChild(getDisplayObject(100, 100));
        _container.rawChildContainer.addChild(getDisplayObject(10, 10));
        _container.rawChildContainer.addChild(getDisplayObject(50, 50));

        _layoutContainer.cellWidth = 40;
    }

    [Test(async)]
    public function shouldDispatchLayoutRefreshWhenCellHeightChanges(): void {
        _layoutContainer.layoutPolicy = LayoutPolicy.VERTICAL_LAYOUT;
        _layoutContainer.addEventListener(LayoutEvent.LAYOUT_REFRESH, Async.asyncHandler(this, function(le: LayoutEvent, obj: Object): void {
            _layoutContainer.removeEventListener(LayoutEvent.LAYOUT_REFRESH, arguments.callee);

            assertEquals(0, _container.getChildAt(0).x);
            assertEquals(0, _container.getChildAt(1).x);
            assertEquals(0, _container.getChildAt(2).x);

            assertEquals(0, _container.getChildAt(0).y);
            assertEquals(40, _container.getChildAt(1).y);
            assertEquals(80, _container.getChildAt(2).y);
        }, 200));

        _container.rawChildContainer.addChild(getDisplayObject(100, 100));
        _container.rawChildContainer.addChild(getDisplayObject(10, 10));
        _container.rawChildContainer.addChild(getDisplayObject(50, 50));

        _layoutContainer.cellHeight = 40;
    }

    [Test(async)]
    public function byDefaultTheItemsShouldLayoutHorizontallyByChildWidthAndIgnoreTheXAndYIfOverwriteIsSetToTrue(): void {
        _layoutContainer.overwritePlacement = true;
        _layoutContainer.addEventListener(LayoutEvent.LAYOUT_REFRESH, Async.asyncHandler(this, function(le: LayoutEvent, obj: Object): void {
            _layoutContainer.removeEventListener(LayoutEvent.LAYOUT_REFRESH, arguments.callee);

            assertEquals(0, _container.getChildAt(0).x);
            assertEquals(100, _container.getChildAt(1).x);
            assertEquals(110, _container.getChildAt(2).x);

            assertEquals(0, _container.getChildAt(0).y);
            assertEquals(0, _container.getChildAt(1).y);
            assertEquals(0, _container.getChildAt(2).y);
        }, 200));

        _container.rawChildContainer.addChild(getDisplayObject(100, 100, 134, 343));
        _container.rawChildContainer.addChild(getDisplayObject(10, 10,432, 325));
        _container.rawChildContainer.addChild(getDisplayObject(50, 50, 3432, 34));

        _layoutContainer.refresh();
    }

    [Test(async)]
    public function byDefaultTheItemsShouldLayoutVerticallyByChildWidthAndIgnoreTheXAndYIfOverwriteIsSetToTrue(): void {
        _layoutContainer.overwritePlacement = true;
        _layoutContainer.layoutPolicy = LayoutPolicy.VERTICAL_LAYOUT;
        _layoutContainer.addEventListener(LayoutEvent.LAYOUT_REFRESH, Async.asyncHandler(this, function(le: LayoutEvent, obj: Object): void {
            _layoutContainer.removeEventListener(LayoutEvent.LAYOUT_REFRESH, arguments.callee);

            assertEquals(0, _container.getChildAt(0).x);
            assertEquals(0, _container.getChildAt(1).x);
            assertEquals(0, _container.getChildAt(2).x);

            assertEquals(0, _container.getChildAt(0).y);
            assertEquals(100, _container.getChildAt(1).y);
            assertEquals(110, _container.getChildAt(2).y);
        }, 200));

        _container.rawChildContainer.addChild(getDisplayObject(100, 100, 134, 343));
        _container.rawChildContainer.addChild(getDisplayObject(10, 10,432, 325));
        _container.rawChildContainer.addChild(getDisplayObject(50, 50, 3432, 34));

        _layoutContainer.refresh();
    }

    [Test(async)]
    public function shouldNotifyTheContainerToRecalculateBoundsIfRefreshed(): void {
        _container.addEventListener(ContainerEvent.RECALCULATE_BOUNDS, Async.asyncHandler(this, function(ce: ContainerEvent, obj: Object): void {
            assertTrue(true);
        }, 200));

        _container.rawChildContainer.addChild(getDisplayObject(100, 100, 134, 343));
        _container.rawChildContainer.addChild(getDisplayObject(10, 10,432, 325));
        _container.rawChildContainer.addChild(getDisplayObject(50, 50, 3432, 34));

        _layoutContainer.refresh();
    }

    private function getDisplayObject(width: Number, height: Number, x: Number = 0, y: Number = 0): DisplayObject {
        var retVal: Shape = new Shape();
        with(retVal.graphics) {
            beginFill(0);
            drawRect(0,0,width, height);
            endFill();
        }
        retVal.x = x;
        retVal.y = y;
        return retVal;
    }
}
}
